DataHub : le tracking serveur opéré par Qwant
Document technique original
Cette page est une synthèse. L'analyse complète, avec la chronologie Git, les catégories d'événements, les fichiers et les commits contrôlés, est disponible ici : Le DataHub de Qwant — journalisation serveur, recherches, clics et publicités.
Avertissement probatoire
Ce chapitre décrit les capacités du code versionné dans le dépôt
API-API-TAG-PACKAGER, en particulier dans le tagv1.32.1du 22 décembre 2016. Une capacité inscrite dans une version de release n'établit pas, à elle seule, son activation sur tout le trafic, la réception de chaque événement, sa durée de conservation ou son exploitation effective par les équipes de Qwant.
1. Réponse synthétique
Le code source établit qu'en 2016 Qwant avait développé un système interne centralisé désigné comme DataHub. Ce système était capable de recevoir des événements concernant :
- les requêtes de recherche ;
- les clics sur les résultats ;
- les impressions publicitaires ;
- les appels aux fournisseurs externes ;
- certaines actions de compte et de boards ;
- les erreurs applicatives ;
- des signaux de lutte contre le scraping et les abus.
Chaque événement pouvait être associé à une enveloppe comprenant notamment :
- l'adresse IP complète vue par l'API ;
- le User-Agent ;
- la locale ;
- l'URI HTTP complète ;
- le référent ;
- la date ;
- l'environnement et la version applicative ;
- à partir d'août 2016, un hash stable dérivé de l'adresse IP.
Cette association répétée entre une action, son contenu, un instant et des identifiants techniques étaye la qualification de tracking serveur individualisable côté Qwant.
Elle ne démontre pas, sans éléments supplémentaires :
- l'identification civile de chaque utilisateur ;
- la constitution effective d'un profil publicitaire longitudinal ;
- une transmission du contenu du DataHub à Microsoft ;
- la durée de conservation des événements ;
- l'utilisation du système pour surveiller une personne déterminée ;
- une faute ou une intention pénale.
2. Qui a mis en place le DataHub ?
L'historique Git attribue l'implémentation principale du nouveau logger à Thomas Decaux.
Le commit structurant est :
48a167106a2bf14b7521767d92242bf41bda6966
31 mars 2016
t.decaux@qwant.com
#QAPI-370 Integrate dataHub aka new logger48a167106a2bf14b7521767d92242bf41bda6966
31 mars 2016
t.decaux@qwant.com
#QAPI-370 Integrate dataHub aka new loggerCe commit ajoute ou transforme notamment :
www/application/config/logger.php;www/application/hooks/QwantHook.php;www/application/libraries/search_service.php;www/application/models/logger.php;- le contrôleur chargé de certains clics.
Pierre Vignaux apparaît ensuite comme le principal intégrateur de la fonctionnalité dans prelive et master, ainsi que comme auteur ou correcteur de plusieurs mécanismes de recherche, de score antispam et de bannissement.
D'autres contributeurs interviennent sur des parties identifiables :
- Nghia Duong sur les exceptions, les erreurs de connexion et
feedSearchSuggest(); - Jonathan Cassar sur certains merges et composants périphériques ;
- Thomas Decaux à nouveau sur les impressions publicitaires, les clics, le hash client et de nombreuses extensions du schéma.
Parmi les étapes importantes :
| Date | Commit | Fonction ajoutée ou modifiée |
|---|---|---|
| 14 juin 2016 | c3c69dff89 |
transport phpAmqpLib et plusieurs serveurs RabbitMQ |
| 21 juillet 2016 | 86e9620bda |
impressions publicitaires |
| 3 août 2016 | 7799a5c560 |
hash client stable et score antispam |
| 31 août 2016 | 4bdfca906f |
détail des annonces publicitaires |
| 7 septembre 2016 | c5f1e1d72d |
actions de compte, boards, notes et contacts |
| 9 septembre 2016 | 451981b7ea |
contrôleur de clics SERP et page d'accueil |
| 5 décembre 2016 | d6aa1cf0c6 |
bannissement distingué comme produit par le DataHub |
Cette attribution est une attribution Git. Elle ne prouve pas qui a décidé les finalités du système, qui connaissait l'ensemble de son périmètre ou qui l'a autorisé au niveau de la direction.
3. Comment fonctionne le DataHub ?
Le chemin visible dans le code est le suivant :
Requête adressée à l'API Qwant
↓
Création d'un ou plusieurs événements
↓
Logger::logEvent()
↓
Tampon en mémoire pendant la requête
↓
QwantHook::onShutDown()
↓
Logger::flushEvents()
↓
Message JSON publié dans RabbitMQ
↓
Consommateurs DataHub absents du dépôt étudiéRequête adressée à l'API Qwant
↓
Création d'un ou plusieurs événements
↓
Logger::logEvent()
↓
Tampon en mémoire pendant la requête
↓
QwantHook::onShutDown()
↓
Logger::flushEvents()
↓
Message JSON publié dans RabbitMQ
↓
Consommateurs DataHub absents du dépôt étudiéLe logger accumule les événements dans un tableau en mémoire. À la fin du traitement, un hook récupère le logger, ajoute éventuellement une erreur PHP fatale puis tente de vider le tampon.
Dans v1.32.1, le transport :
- utilise
AMQPStreamConnection; - essaie plusieurs hôtes ;
- se connecte sur le port
5672; - publie dans l'échange
amq.direct; - utilise la routing key
v1; - encode chaque événement en JSON.
La configuration dite de production vise deux adresses IP privées. La configuration générale utilise un hostname interne contenant queue.analytics.qwant.plive.
Le dépôt ne contient pas le consommateur de la queue. Il ne permet donc pas de déterminer directement :
- la base de données finale ;
- les index ou tables créés ;
- les durées de conservation ;
- les tableaux de bord ;
- les personnes habilitées ;
- les traitements statistiques effectivement appliqués.
Le code ignore aussi les exceptions de connexion et ne montre pas d'accusé de réception du broker. Il prouve une tentative d'envoi, pas la réception certaine de chaque message.
4. L'enveloppe commune de chaque événement
Logger::logEvent() ajoute automatiquement plusieurs blocs aux données propres à l'événement.
| Bloc | Données principales |
|---|---|
| Événement | date Unix, identifiant, nom et version du schéma |
| Produit | module, version, environnement, type d'API et application |
| Client | IP complète, origine réseau, locale, User-Agent et hash client |
| Requête HTTP | méthode, host, URI, serveur, référent et score antispam |
| Données métier | recherche, clic, publicité, erreur ou action concernée |
Le système n'enregistre donc pas seulement un compteur anonyme. Il peut associer le contenu de l'action aux métadonnées techniques de la connexion.
IP complète et hash stable
Pour chaque événement, le champ client.ip reçoit l'adresse retournée par ip_address().
À partir du 3 août 2016, une IP publique reçoit également un hash calculé selon le principe :
SHA-256(IP + sel serveur)SHA-256(IP + sel serveur)À sel inchangé, une même IP produit le même hash dans des événements successifs. Ce mécanisme permet techniquement de rapprocher des événements associés à une même adresse au cours du temps.
Il ne constitue pas un identifiant certain de personne : une IP peut être partagée, dynamique, masquée par un VPN ou utilisée par plusieurs membres d'un foyer ou d'une entreprise.
Identifiant d'événement
L'identifiant propre à chaque événement contient également :
- le mois, le jour et l'heure ;
- le produit et le type d'événement ;
- un fragment de MD5 fondé sur
IP + User-Agent; - une partie aléatoire.
5. Ce que le DataHub enregistre sur les recherches
Dans v1.32.1, l'événement search comporte notamment :
- la requête complète ;
- la locale ;
- le domaine de recherche ;
- l'offset et le nombre de résultats demandés ;
- le nombre de résultats obtenus ;
- le statut du cache ;
- l'onglet ;
- la durée ;
- les filtres ;
- le score antispam ;
- le statut HTTP.
search_service.php appelle le logger aussi bien :
- après une recherche exécutée par un fournisseur ou modèle ;
- lorsque le résultat est resservi depuis le cache ;
- pour certains motifs bloqués comme abusifs.
Le cache ne supprime donc pas le tracking de la requête : il change la valeur du champ cached.
Toutes les tentatives ne sont pas nécessairement enregistrées sous forme d'événement search. Certaines validations peuvent retourner avant l'appel à logSearch(), et une exception peut produire seulement un événement d'erreur.
6. Les clics sur les résultats
Le contrôleur LoggerClickAPIController prévoit une route de type :
api/click/(:any)api/click/(:any)Lorsqu'un clic valide lui est transmis, l'événement peut contenir :
- la requête ;
- l'URL cible complète ;
- le host, le schéma et le domaine cible ;
- la position du résultat ;
- le domaine de recherche ;
- le type de lien, notamment publicité ou résultat normal ;
- la locale ;
- l'appareil ;
- l'onglet.
Le code prévoit aussi des événements pour :
- les clics sur la page d'accueil ;
- les clics Cinetick, avec film, cinéma, ville et séance.
Le dépôt API prouve ce que l'endpoint fait lorsqu'il est appelé. Il ne prouve pas que toutes les interfaces Qwant lui adressaient systématiquement chaque clic. Le code front ou des traces réseau seraient nécessaires pour mesurer cette couverture.
7. Les impressions publicitaires
Lorsque search_ads.php interroge Bing Ads, Qwant construit parallèlement un événement interne ads_print contenant :
- le mot-clé recherché ;
- l'appareil ;
- la locale ;
- l'onglet ;
- le domaine ;
- le nombre d'annonces ;
- le titre et l'URL source de chaque annonce retournée.
L'enveloppe DataHub ajoute l'IP complète, le hash de l'IP, le User-Agent et le contexte HTTP.
La portée la plus solide est donc :
Qwant disposait d'un événement interne capable de rapprocher une requête publicitaire, les annonces affichées et des identifiants techniques côté serveur.
Le code ne suffit pas à démontrer que ces données ont été transformées en profil publicitaire individuel durable.
8. Ne pas confondre DataHub Qwant et flux Bing
Le parcours publicitaire comporte deux flux distincts.
Flux adressé à Bing Ads
Le code adresse à Bing Ads :
- la requête ;
- le User-Agent ;
- le référent ;
- un header
X-Search-ClientIP.
Pour une IPv4, anonymizeIp() remplace le dernier octet par zéro :
82.65.234.124 → 82.65.234.082.65.234.124 → 82.65.234.0La fonction ne traite que les adresses contenant un point. Une IPv6 pourrait donc être renvoyée inchangée dans ce chemin, sous réserve du format reçu en production.
Flux interne DataHub
Le DataHub Qwant reçoit, dans son enveloppe commune, l'IP complète vue par l'API. Il serait donc erroné d'écrire que le DataHub ne conservait que l'IPv4 tronquée au /24.
Inversement, aucun code contrôlé ne montre que le contenu du DataHub interne était envoyé à Microsoft. La transmission à Bing et la journalisation interne Qwant doivent être analysées séparément.
Pour l'articulation avec Microsoft et les politiques de confidentialité, voir également le chapitre 44 et le chapitre 53 sur l'IP /24.
search_suggest
La fonction feedSearchSuggest() enregistre séparément les recherches Web normalisées dans une table SQL search_suggest.
Elle calcule un hash journalier incorporant :
- la date ;
- l'IP ;
- la locale ;
- la requête.
La requête et la locale sont insérées dans la table. Le commentaire indique que ces données doivent servir à l'optimisation des suggestions.
Ce mécanisme n'utilise pas le transport RabbitMQ du DataHub. Le TTL d'une heure visible dans la fonction concerne le cache de déduplication, pas la durée de conservation SQL.
click_url_temp
Après un clic SERP, url_model->saveUrl() écrit aussi dans un index Elasticsearch nommé click_url_temp :
- le hash journalier ;
- l'URL ;
- la requête ;
- la locale ;
- la position ;
- la date.
Un clic reçu peut donc alimenter à la fois le DataHub et un document Elasticsearch distinct. Le mot temp ne suffit pas à établir une durée d'effacement.
10. Autres événements suivis
Le DataHub ne se limite pas à la recherche et à la publicité.
| Produit | Exemples d'événements |
|---|---|
| Compte | inscription, suppression demandée ou exécutée, erreur de connexion, flood |
| Boards | création de board, création de note, flood |
| Core | contact et feedback |
| IA | requête réussie et clic Cinetick |
| API | erreur PHP, exception, erreur 404 et ancien logger |
| Fournisseurs externes | URL appelée, host, code HTTP, durée et volume téléchargé |
Certaines actions de compte ou de board contiennent un identifiant numérique d'utilisateur. L'événement standard de recherche ne contient pas directement cet identifiant. Le dépôt ne montre pas une jointure systématique entre les recherches et un compte nommé.
11. Une fonction opérationnelle d'antiflood
Le DataHub n'est pas seulement présenté comme un outil d'analytics.
Dans user_model.php, isBannedByDataHub() consulte dans Couchbase une clé calculée à partir du même hash salé de l'IP. Le commentaire indique :
Checks in couchbase generated by DataHub if an IP is banned
Dans MY_Controller.php, l'existence de cette clé peut provoquer une réponse :
429 Too Many Requests429 Too Many RequestsLe code distingue ce bannissement de ceux fondés sur une blacklist IP classique ou sur IP + User-Agent.
Cette boucle est donc visible :
Événements et hash client
↓
Traitement DataHub absent du dépôt
↓
Clé de blacklist Couchbase
↓
Refus d'accès par l'APIÉvénements et hash client
↓
Traitement DataHub absent du dépôt
↓
Clé de blacklist Couchbase
↓
Refus d'accès par l'APILe dépôt ne contient pas l'algorithme qui décide de créer la clé. Les critères, seuils et durées du bannissement restent inconnus.
12. Tracking serveur sans cookie
Le logger étudié :
- ne dépose pas lui-même de cookie ;
- ne charge pas de pixel ;
- n'exécute pas de script de fingerprinting dans le navigateur ;
- utilise les données de la requête HTTP et les paramètres transmis à l'API.
L'absence de cookie ne signifie donc pas l'absence de tracking. Il faut distinguer :
- le traceur client, déposé ou exécuté dans le navigateur ;
- le tracking serveur, qui associe des actions successives à des identifiants techniques reçus par le serveur.
Dans les producteurs contrôlés, aucune condition liée à DNT, au consentement ou à une opposition utilisateur n'est visible avant l'enregistrement. La seule exclusion concerne les User-Agents techniques qwant-monitor et qwant-stresstest, sauf pour les erreurs.
13. Ce que le code prouve
Le dépôt permet d'affirmer que :
- le terme DataHub est explicitement employé ;
- une architecture d'envoi JSON vers une queue analytics interne est implémentée ;
- les événements peuvent contenir l'IP complète, le User-Agent, l'URI et le référent ;
- un hash stable de l'IP est ajouté à partir d'août 2016 ;
- les recherches ordinaires et celles servies depuis le cache peuvent être journalisées ;
- les clics et les impressions publicitaires disposent d'événements dédiés ;
- les annonces affichées peuvent être enregistrées avec la requête correspondante ;
- des actions de compte et de contenu alimentent aussi le système ;
- une blacklist générée en aval par le DataHub peut conduire à refuser l'accès à l'API ;
- des tags de release et une configuration nommée
productioncontiennent ce mécanisme.
14. Ce qui reste à démontrer
Le code seul ne permet pas d'établir :
- le déploiement de chaque version sur tout le trafic ;
- la réception de chaque message ;
- le schéma du stockage aval ;
- les durées de conservation ;
- les habilitations d'accès ;
- les traitements statistiques réellement effectués ;
- la constitution d'un profil publicitaire longitudinal par personne ;
- la correspondance entre un hash et une identité civile ;
- la transmission du DataHub à Microsoft ;
- le suivi d'une personne déterminée ;
- une faute juridique ou une intention de dissimulation.
15. Conclusion probatoire
La formulation la plus étayée est la suivante :
Dès 2016, Qwant avait développé et versionné un dispositif interne de journalisation serveur désigné comme DataHub. Dans le tag
v1.32.1, ce dispositif était capable d'enregistrer les requêtes de recherche, les clics et les impressions publicitaires avec l'adresse IP complète, le User-Agent, le contexte HTTP et un hash stable dérivé de l'IP. Il permettait ainsi un tracking serveur individualisable côté Qwant et alimentait aussi une fonction de lutte contre les abus. Le code établit cette capacité technique et son inclusion dans des versions de release ; il ne suffit pas à démontrer son déploiement sur tout le trafic, ses durées de conservation, la constitution effective d'un profil publicitaire longitudinal ou une transmission du DataHub à Microsoft.
Cette conclusion complète le chapitre 44 : le tracking n'est pas seulement un flux adressé à Bing. Le code montre aussi une journalisation détaillée opérée sur l'infrastructure de Qwant.
16. Source principale et références
- Document technique original : Le DataHub de Qwant — journalisation serveur, recherches, clics et publicités
- Chapitre 44 — Continuité du « mensonge » de Qwant : indépendance, Microsoft et confidentialité
- Chapitre 53 — L'avertissement, le suivi des tweets et le problème de l'IP
/24
Principaux fichiers contrôlés dans v1.32.1 :
www/application/models/logger.php;www/application/hooks/QwantHook.php;www/application/config/production/logger.php;www/application/libraries/search_service.php;www/application/controllers/LoggerClickAPIController.php;www/application/models/search/search_ads.php;www/application/models/httpgateway.php;www/application/models/user_model.php;www/application/core/MY_Controller.php.